/*
  This file is part of JCM.

  JCM is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  JCM is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with JCM.  If not, see <http://www.gnu.org/licenses/>.
*/
import java.util.Calendar;

/**
 * Padrões monetários do Brasil ao longo do tempo.
 *
 * Nota: O nome dessa classe era Currency, modificado para o atual para
 *       evitar ambiguidade com a classe de mesmo nome distribuída no
 *       JRE Java desde a versão 1.4.
*/
public class Moeda
{
  /** Array das datas de mudanças de padrão monetário no formato UNIX timestamp. */
  private long[] datas;

  /** Índice do padrão monetário mais recentemente pesquisado. */
  private int index;

  /** Construtor visando modelo Singleton. */
  protected Moeda()
  {
    // inicializa um Calendar normalizado tal que
    // a granularidade de tempo abaixo de dia é zero
    Calendar c = Calendar.getInstance();
    c.set(Calendar.HOUR_OF_DAY, 0);
    c.set(Calendar.MINUTE, 0);
    c.set(Calendar.SECOND, 0);
    c.set(Calendar.MILLISECOND, 0);
    // inicializa o array de datas no formato timestamp UNIX
    datas = new long[dates.length];
    index = -1;
    // loop de preenchimento do array de datas
    for (int[] date: dates)
    {
      c.set(date[0], date[1], date[2]);
      datas[++index] = c.getTimeInMillis();
    }
  }

  /** Apontador para instância única desse objeto. */
  static private Moeda instance = null;

  /** Método para acessar a instância única desse objeto. */
  static public Moeda getInstance()
  {
    if (instance == null) instance = new Moeda();
    return instance;
  }

  /**
   * Pesquisa da moeda na data fornecida tal que a data apontada pelo
   * índice ao final da pesquisa é a data de mudança mais recente.
   *
   * @param calendar Data alvo da pesquisa.
  */
  public void search(Calendar calendar)
  {
    search(calendar.getTimeInMillis());
  }

  /**
   * Pesquisa da moeda em conformidade com o timestamp fornecido.
   *
   * @param t Timestamp UNIX da data alvo da pesquisa.
  */
  public void search(long t)
  {
    // índice da data mais moderna
    index = datas.length - 1;
    // loop de pesquisa procurando a última data anterior à data fornecida
    while ((index > 0) && (t < datas[index])) index--;
  }

  /** Incrementa o índice da data pesquisada mais recentemente. */
  public void next() { if (index+1 < datas.length) index++; }

  /**
   * Retorna o UNIX timestamp da data mais recentemente pesquisada.
   *
   * @return O UNIX timestamp da data mais recentemente pesquisada.
  */
  public long getTime() { return datas[index]; }

  /**
   * Retorna o nome da moeda em conformidade com
   * a data mais recentemente pesquisada.
   *
   * @return A string contendo o nome da moeda pesquisada.
  */
  public String getName() { return getName(true); }

  /**
   * Retorna o nome da moeda depois ou antes da
   * data mais recentemente pesquisada.
   *
   * @param notBefore Indicador lógico do momento usado na pesquisa.
   * @return A string contendo o nome da moeda pesquisada.
  */
  public String getName(boolean notBefore)
  {
    return nomes[notBefore ? index + 1 : index];
  }

  /**
   * Retorna o símbolo da moeda em conformidade com a data mais
   * recentemente pesquisada para o momento "atual ou após".
   *
   * @return A string contendo o símbolo da moeda pesquisada.
  */
  public String getSymbol() { return getSymbol(true); }

  /**
   * Retorna o símbolo da moeda depois (inclusive) ou antes
   * da data mais recentemente pesquisada.
   *
   * @param notBefore Indicador lógico do momento usado na pesquisa.
   * @return A string contendo o símbolo da moeda pesquisada.
  */
  public String getSymbol(boolean notBefore)
  {
    return simbolos[notBefore ? index + 1 : index];
  }

  /**
   * Array das datas de mudanças de padrão monetário no formato ano/mês/dia.
  */
  static private int[][] dates =
  {
    { 1942, Calendar.NOVEMBER, 01 },
    { 1967, Calendar.FEBRUARY, 13 },
    { 1970, Calendar.MAY,      15 },
    { 1986, Calendar.FEBRUARY, 28 },
    { 1989, Calendar.JANUARY,  16 },
    { 1990, Calendar.MARCH,    16 },
    { 1993, Calendar.AUGUST,   01 },
    { 1994, Calendar.JULY,     01 }
  };

  /** Array dos nomes das moedas por extenso. */
  static private String[] nomes =
  {
    "REAL",           // anterior a 01/Nov/1942
    "CRUZEIRO",       // anterior a 13/Fev/1967
    "CRUZEIRO NOVO",  // anterior a 15/Mai/1970
    "CRUZEIRO",       // anterior a 28/Fev/1986
    "CRUZADO",        // anterior a 16/Jan/1989
    "CRUZADO NOVO",   // anterior a 16/Mar/1990
    "CRUZEIRO",       // anterior a 01/Ago/1993
    "CRUZEIRO REAL",  // anterior a 01/Jul/1994
    "REAL"            // moeda atual
  };

  /** Array dos símbolos das moedas. */
  static private String[] simbolos =
  {
    "$",    // anterior a 01/Nov/1942
    "Cr$",  // anterior a 13/Fev/1967
    "NCr$", // anterior a 15/Mai/1970
    "Cr$",  // anterior a 28/Fev/1986
    "Cz$",  // anterior a 16/Jan/1989
    "NCz$", // anterior a 16/Mar/1990
    "Cr$",  // anterior a 01/Ago/1993
    "CR$",  // anterior a 01/Jul/1994
    "R$"    // moeda atual
  };
}
